package com.ruoyi.common.utils.excel;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelStyleType;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.ruoyi.common.config.RuoYiConfig;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 导入导出工具类
 */
public class ExcelUtiles {
    /**
     * @Description 根据上传的excel文件查询对应shell页
     * @Date 13:21 2025/7/26
     * @Param [file]
     **/
    public static List<Map<String, Object>> excelFileShell(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        List<Map<String, Object>> list = new ArrayList<>();//存放excel对应不同shell页
        //获取文件后缀
        String extension = "." + FilenameUtils.getExtension(fileName);
        //生成新的文件名称
        String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + UUID.randomUUID().toString().replace("-", "") + extension;
        // 根据日期生成目录
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        // 本地资源路径
        String localPath = RuoYiConfig.getProfile();
        String dateDirPath = localPath;
        File dateDir = new File(dateDirPath);
        if (!dateDir.exists())
            dateDir.mkdirs();
        File dir = new File(dateDirPath);
        // 处理文件上传
        try {
            file.transferTo(new File(dir, newFileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String s = dir + "/" + newFileName;
        try {
            // 创建文件输入流
            FileInputStream fis = new FileInputStream(new File(s));
            // 根据输入流创建工作簿
            Workbook workbook = WorkbookFactory.create(fis);
            // 获取Sheet数量
            int sheetCount = workbook.getNumberOfSheets();
            // 存储Sheet名称的列表
            List<String> sheetNames = new ArrayList<>();
            // 遍历所有Sheet
            for (int i = 0; i < sheetCount; i++) {
                // 获取当前Sheet
                Sheet sheet = workbook.getSheetAt(i);
                // 获取Sheet名称
                String sheetName = sheet.getSheetName();
                // 存储Sheet名称
                sheetNames.add(sheetName);
            }
            // 输出Sheet名称列表
            System.out.println("Sheet Names:");
            int i = 1;
            for (String sheetName : sheetNames) {
                Map<String, Object> mapdata = new HashMap<>();
                mapdata.put("sheetName", sheetName);
                mapdata.put("sheetNum", i);
                list.add(mapdata);
                i++;
                System.out.println(sheetName);
            }
            // 关闭工作簿和文件输入流
            workbook.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * @return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @Author yrb
     * @Description // 根据路径查询excel文件的sheet页
     * @Date 13:43 2023/7/24
     * @Param [file]
     **/
    public static List<Map<String, Object>> excelFileShellurl(String file) {
        List<Map<String, Object>> list = new ArrayList<>();//存放excel对应不同shell页
        try {
            // 创建文件输入流
            FileInputStream fis = new FileInputStream(new File(file));
            // 根据输入流创建工作簿
            Workbook workbook = WorkbookFactory.create(fis);
            // 获取Sheet数量
            int sheetCount = workbook.getNumberOfSheets();
            // 存储Sheet名称的列表
            List<String> sheetNames = new ArrayList<>();
            // 遍历所有Sheet
            for (int i = 0; i < sheetCount; i++) {
                // 获取当前Sheet
                Sheet sheet = workbook.getSheetAt(i);
                // 获取Sheet名称
                String sheetName = sheet.getSheetName();
                // 存储Sheet名称
                sheetNames.add(sheetName);
            }
            // 输出Sheet名称列表
            System.out.println("Sheet Names:");
            int i = 0;
            for (String sheetName : sheetNames) {
                Map<String, Object> mapdata = new HashMap<>();
                mapdata.put("sheetName", sheetName);
                mapdata.put("sheetNum", i);
                list.add(mapdata);
                i++;
                System.out.println(sheetName);
            }
            // 关闭工作簿和文件输入流
            workbook.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 导出Excel
     *
     * @param sheetName sheet名称
     * @param title     标题
     * @param values    内容
     * @param wb        HSSFWorkbook对象
     * @return
     */
    public static XSSFWorkbook getXSSFWorkbook(String sheetName, String[] title, String[][] values, XSSFWorkbook wb) {

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if (wb == null) {
            wb = new XSSFWorkbook();
        }

        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        XSSFSheet sheet = wb.createSheet(sheetName);

        // 设置列宽
        sheet.setColumnWidth(0, 256 * 5);
        sheet.setColumnWidth(1, 256 * 33);
        sheet.setColumnWidth(2, 256 * 30);
        sheet.setColumnWidth(3, 256 * 15);
        sheet.setColumnWidth(4, 256 * 25);
        sheet.setColumnWidth(5, 256 * 25);
        sheet.setColumnWidth(6, 256 * 25);
        sheet.setColumnWidth(7, 256 * 25);
        sheet.setColumnWidth(8, 256 * 25);
        sheet.setColumnWidth(9, 256 * 15);
        sheet.setColumnWidth(10, 256 * 15);

        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        Row row = sheet.createRow(0);

        // 第四步，创建单元格，并设置值表头 设置表头居中
        XSSFCellStyle style = wb.createCellStyle();
        //style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式

        // 声明列对象
        Cell cell = null;

        // 创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }

        // 创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                // 将内容按顺序赋给对应的列对象
                row.createCell(j).setCellValue(values[i][j]);
            }
        }
        return wb;
    }

    // 发送响应流方法
    public static  void setResponseHeader(HttpServletResponse response, String fileName) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
            String codedFileName = URLEncoder.encode(fileName, "UTF-8");
            response.setHeader("content-disposition", ";filename=" + codedFileName + ".xlsx");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 功能描述：复杂导出Excel，包括文件名以及表名。创建表头
     *
     * @param list           导出的实体类
     * @param title          表头名称
     * @param sheetName      sheet表名
     * @param pojoClass      映射的实体类
     * @param isCreateHeader 是否创建表头
     * @param fileName
     * @param response
     * @return
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
                                   boolean isCreateHeader, HttpServletResponse response) {
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * 功能描述：复杂导出Excel，包括文件名以及表名,不创建表头
     *
     * @param list      导出的实体类
     * @param title     表头名称
     * @param sheetName sheet表名
     * @param pojoClass 映射的实体类
     * @param fileName
     * @param response
     * @return
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
                                   HttpServletResponse response) {
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    /**
     * 功能描述：Map 集合导出
     *
     * @param list     实体集合
     * @param fileName 导出的文件名称
     * @param response
     * @return
     */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        defaultExport(list, fileName, response);
    }

    /**
     * 功能描述：默认导出方法
     *
     * @param list         导出的实体集合
     * @param fileName     导出的文件名
     * @param pojoClass    pojo实体
     * @param exportParams ExportParams封装实体
     * @param response
     * @return
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response,
                                      ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        if (workbook != null) {
            downLoadExcel(fileName, response, workbook);
        }
    }

    /**
     * 功能描述：Excel导出
     *
     * @param fileName 文件名称
     * @param response
     * @param workbook Excel对象
     * @return
     */
    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            // throw new NormalException(e.getMessage());
        }
    }

    /**
     * 功能描述：默认导出方法
     *
     * @param list     导出的实体集合
     * @param fileName 导出的文件名
     * @param response
     * @return
     */
    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        if (workbook != null)
            ;
        downLoadExcel(fileName, response, workbook);
    }

    /**
     * 功能描述：根据文件路径来导入Excel
     *
     * @param filePath   文件路径
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer sheetNum, Integer titleRows, Integer headerRows, Class<T> pojoClass, ClassExcelVerifyHandler verifyHandler) {
        // 判断文件是否存在
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        //注意：导入实体类要用驼峰 首字母小写
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setSheetNum(sheetNum);
        params.setVerifyHandler(verifyHandler);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
//            throw new RuntimeException("模板不能为空");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();

        }
        return list;
    }

    /**
     * 功能描述：根据文件路径来导入Excel
     *
     * @param filePath   文件路径
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass, ClassExcelVerifyHandler verifyHandler) {
        // 判断文件是否存在
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setVerifyHandler(verifyHandler);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
//            throw new RuntimeException("模板不能为空");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();

        }
        return list;
    }

    /**
     * 功能描述：根据文件路径来导入Excel
     *
     * @param filePath   文件路径
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        // 判断文件是否存在
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
//            throw new RuntimeException("模板不能为空");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();

        }
        return list;
    }

    /**
     * 功能描述：根据接收的Excel文件来导入Excel,并封装成实体类
     *
     * @param file       上传的文件
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  Excel实体类
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows,
                                          Class<T> pojoClass) {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (NoSuchElementException e) {
            // throw new NormalException("excel文件不能为空");
        } catch (Exception e) {
            // throw new NormalException(e.getMessage());
            System.out.println(e.getMessage());
        }
        return list;
    }

    /**
     * 得到Workbook对象
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static Workbook getWorkBook(MultipartFile file) throws IOException {
        // 这样写 excel 能兼容03和07
        InputStream is = file.getInputStream();
        Workbook hssfWorkbook = null;
        try {
            hssfWorkbook = new HSSFWorkbook(is);
        } catch (Exception ex) {
            is = file.getInputStream();
            hssfWorkbook = new XSSFWorkbook(is);
        }
        return hssfWorkbook;
    }

    /**
     * 得到错误信息
     *
     * @param sb
     * @param list
     * @param i
     * @param obj
     * @param name 用哪个属性名去表明不和规定的数据
     * @param msg
     * @throws Exception
     */
    public static void getWrongInfo(StringBuilder sb, List list, int i, Object obj, String name, String msg)
            throws Exception {
        Class clazz = obj.getClass();
        Object str = null;
        // 得到属性名数组
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            if (f.getName().equals(name)) {
                // 用来得到属性的get和set方法
                PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
                // 得到get方法
                Method getMethod = pd.getReadMethod();
                str = getMethod.invoke(obj);
            }
        }
        if (i == 0) {
            sb.append(msg + str + ";");
        } else if (i == (list.size() - 1)) {
            sb.append(str + "</br>");
        } else {
            sb.append(str + ";");
        }
    }

    /**
     * @param workbook
     * @param sheetNum   (sheet的位置，0表示第一个表格中的第一个sheet)
     * @param sheetTitle （sheet的名称）
     * @param headers    （表格的标题）
     * @param （表格的数据）
     * @param out        （输出流）
     * @throws Exception
     * @Title: exportExcel
     * @Description: 导出Excel的方法
     * @author: evan @ 2014-01-09
     */
    public void exportExcel(XSSFWorkbook workbook, int sheetNum, String sheetTitle, String[] headers, String[][] values,
                            OutputStream out) throws Exception {
        // 生成一个表格
        XSSFSheet sheet = workbook.createSheet();
        workbook.setSheetName(sheetNum, sheetTitle);
        // 设置表格默认列宽度为20个字节
        sheet.setDefaultColumnWidth((short) 20);
        // 生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
		/*style.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);*/
        // 生成一个字体
        XSSFFont font = workbook.createFont();
        //font.setColor(HSSFColor.BLACK.index);
        font.setFontHeightInPoints((short) 12);
        //font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);

        // 指定当单元格内容显示不下时自动换行
        style.setWrapText(true);

        // 产生表格标题行
        XSSFRow row = sheet.createRow(0);
        for (int i = 0; i < headers.length; i++) {
            XSSFCell cell = row.createCell((short) i);

            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text.toString());
        }

        // 创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                // 将内容按顺序赋给对应的列对象
                row.createCell(j).setCellValue(values[i][j]);
            }
        }
    }

    /**
     * 获取单元格值,不转换值的类型
     *
     * @param row    获取的行
     * @param column 获取单元格列号
     * @return 单元格值
     */
    public Object getCellValue(Row row, int column) {
        if (row == null) {
            return row;
        }
        Object val = "";
        try {
            Cell cell = row.getCell(column);
            if (cell != null && !"".equals(cell)) {
                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) {
                    val = cell.getNumericCellValue();
                    if (DateUtil.isCellDateFormatted(cell)) {
                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
                    } else {
                        if ((Double) val % 1 != 0) {
                            val = new BigDecimal(val.toString());
                        } else {
                            val = new DecimalFormat("0").format(val);
                        }
                    }
                } else if (cell.getCellType() == CellType.STRING) {
                    val = cell.getStringCellValue();
                } else if (cell.getCellType() == CellType.BOOLEAN) {
                    val = cell.getBooleanCellValue();
                }
                //解决导入Java 读取Excel百分数保留原格式（即不转换为小数）的方法
                else if (cell.getCellType() == CellType.FORMULA) {
                    if (cell.getCellStyle().getDataFormatString().indexOf("%") != -1) {
                        val = cell.getNumericCellValue() * 100 + "%";
                    }
                } else if (cell.getCellType() == CellType.ERROR) {
                    val = cell.getErrorCellValue();
                }

            }
        } catch (Exception e) {
            return val;
        }
        return val;
    }

    public static String getCellValueAsString(Cell cell) {
        if (cell.getCellType() == CellType.STRING) {
            return cell.getStringCellValue();
        } else if (cell.getCellType() == CellType.NUMERIC) {
            double numericCellValue = cell.getNumericCellValue();
            if (numericCellValue == -1.0) {
                String data = String.valueOf(numericCellValue);
                String substring = data.substring(0, data.indexOf("."));
                return substring;
            }
            return String.valueOf(numericCellValue);
        } else if (cell.getCellType() == CellType.BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else {
            return "";
        }
    }


    /**
     * 简化调用：默认导出为 xlsx 格式
     */
    public static void exportMapList(HttpServletResponse response,
                                     List<Map<String, Object>> dataList,
                                     String title,
                                     String sheetName,
                                     String fileName) throws IOException {
        exportMapList(response, dataList, title, sheetName, fileName, true);
    }

    /**
     * 导出 Excel（支持 xls 和 xlsx 格式）
     *
     * @param response  Http 响应对象（用于浏览器下载）
     * @param dataList  待导出数据（Map 的 key 为表头，value 为单元格值）
     * @param title     Excel 标题（显示在表头上方）
     * @param sheetName 工作表名称
     * @param fileName  导出文件名（不含后缀）
     * @param isXlsx    是否导出为 xlsx 格式（true 为 xlsx，false 为 xls）
     * @throws IOException 流操作异常
     */
    public static void exportMapList(HttpServletResponse response, List<Map<String, Object>> dataList, String title, String sheetName, String fileName, boolean isXlsx) throws IOException {
        // 1. 配置导出参数
        ExportParams exportParams = new ExportParams();
        exportParams.setTitle(title); // 设置标题
        exportParams.setSheetName(sheetName); // 设置工作表名称
        exportParams.setType(isXlsx ? ExcelType.XSSF : ExcelType.HSSF); // 设置文件类型

// 2. 生成 Excel 工作簿
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, new ArrayList<>(), dataList);
// 3. 配置响应头（解决中文乱码和文件下载）
        response.setContentType(isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encodedFileName + (isXlsx ? ".xlsx" : ".xls"));
// 4. 写入响应流
        try (OutputStream os = response.getOutputStream()) {
            workbook.write(os);
            os.flush();
        } finally {
            // 关闭工作簿释放资源
            if (workbook != null) {
                workbook.close();
            }
        }
    }

    /**
     * 简化版导出方法
     */
    public static void simpleExport(HttpServletResponse response,
                                    List<Map<String, Object>> dataList,
                                    String fileName) throws IOException {

        if (dataList == null || dataList.isEmpty()) {
            throw new RuntimeException("导出数据不能为空");
        }

        // 自动从第一条数据获取列名
        Map<String, String> columnConfig = new HashMap<>();
        Map<String, Object> firstRow = dataList.get(0);
        for (String key : firstRow.keySet()) {
            columnConfig.put(key, key); // 使用字段名作为列显示名
        }

        exportMapToExcel(response, dataList, columnConfig, fileName, "Sheet1", null);
    }

    /**
     * 导出Map数据到Excel
     * @param response HttpServletResponse
     * @param dataList 数据列表
     * @param columnConfig 列配置 Map<字段名, 列显示名称>
     * @param fileName 文件名（不带后缀）
     * @param sheetName 工作表名
     * @param title 标题
     */
    public static void exportMapToExcel(HttpServletResponse response,
                                        List<Map<String, Object>> dataList,
                                        Map<String, String> columnConfig,
                                        String fileName,
                                        String sheetName,
                                        String title) throws IOException {

        // 构建列实体列表
        List<ExcelExportEntity> columnList = buildColumnEntities(columnConfig);

        // 设置导出参数
        ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);
        exportParams.setStyle(ExcelStyleType.BORDER.getClazz());

        // 生成工作簿
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, columnList, dataList);

        // 设置响应头
//        setResponseHeader(response, fileName);

        // 输出文件
//        workbook.write(response.getOutputStream());
//        workbook.close();

        // 3. 配置响应头（解决中文乱码和文件下载）
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encodedFileName +  ".xlsx");
// 4. 写入响应流
        try (OutputStream os = response.getOutputStream()) {
            workbook.write(os);
            os.flush();
        } finally {
            // 关闭工作簿释放资源
            if (workbook != null) {
                workbook.close();
            }
        }
    }

    /**
     * 构建列配置实体
     */
    private static List<ExcelExportEntity> buildColumnEntities(Map<String, String> columnConfig) {
        List<ExcelExportEntity> columnList = new ArrayList<>();

        for (Map.Entry<String, String> entry : columnConfig.entrySet()) {
            ExcelExportEntity column = new ExcelExportEntity(entry.getValue(), entry.getKey());
            column.setWidth(15D);
            columnList.add(column);
        }

        return columnList;
    }



}
